/******************************************************************************************************
Copyright (C) 2013 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

/*globals Env, draw, mainWindow, qsTr, Settings, Application*/
/*jslint plusplus: true, indent: 4, loopfunc: true*/

function GraphReporterBase() {
	"use strict";
	
	this.fName = "Report Name";
}

GraphReporterBase.prototype.report = function (aGraph, aCreateItem, aHtml, aSettings) {
	"use strict";
	
	throw qsTr("Invalid Report");
};

/******************************************************************************/

function DefaultGraphReporter() {
	"use strict";
	GraphReporterBase.call(this);
	
	this.fName = "Default Report";
}

DefaultGraphReporter.prototype = new GraphReporterBase();

DefaultGraphReporter.prototype.report = function (aGraph, aCreateItem, aHtml, aSettings) {
	'use strict';
	var sCount, s, fitModels, yModels, reportText, graphProperties, horzAxsLabel, 
		yModelLabel, formula, parameters, template, parametersStr, p, parameterTemplate,
		textItem, htmlTemplate, oldLTCount, reportParamTemplate;

	if (aGraph === undefined || !aGraph.isValid()) {
		throw new Error("Invalid Graph");
	}

	htmlTemplate = "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"><title>Graph Report</title></head><body>%1</body></html>"; //%1 html body
	if (aHtml) {
		template = "<p><b>%1' = %2</b><br/>%3<br/>Error: %4</p>"; //%1: label, %2: formula, %3: parameters, %4: comments
	} else {
		template = "%1' = %2\n%3\nError: %4\n";
	}
	parameterTemplate = '%1=%2;'; //%1: name, %2: value
	reportParamTemplate = "%1(%2)=%3"; //%1: name, %2: formula, %3 value
	reportText = '';
	sCount = aGraph.seriesCount;
	fitModels = aGraph.fitModels;
	yModels = aGraph.yModels;
	graphProperties = aGraph.graphicProperties;
	horzAxsLabel = graphProperties.horzAxis.label;
	horzAxsLabel = horzAxsLabel.replace(/\([\w\W]*\)/, '');
	for (s = 0; s < sCount; ++s) {
		yModelLabel = yModels[s].label;
		if (yModelLabel.length === 0) {
			if (s === 0) {
				yModelLabel = 'Y';
			} else {
				yModelLabel = 'Y%1'.arg(s);
			}
		}
		formula = fitModels[s].formula;
		if (formula.length !== 0) {
			formula = formula.replace(/exp/g, 'EXP');
			formula = formula.replace(/x/g, horzAxsLabel);
			formula = formula.replace(/EXP/g, 'exp');
			parameters = fitModels[s].fitParams;
			parametersStr = '';

			Object.keys(parameters).forEach(function (p) {
				if (parametersStr.length !== 0) {
					parametersStr += ' ';
				}
				parametersStr += parameterTemplate.arg(p).arg(parameters[p].toPrecision(aSettings.fDecimals));
			});

			parameters = fitModels[s].reportParams;
			Object.keys(parameters).forEach(function (p) {
				if (parametersStr.length !== 0) {
					parametersStr += ' ';
				}
				parametersStr += reportParamTemplate.arg(p).arg(parameters[p].Formula).arg(parameters[p].Value.toPrecision(aSettings.fDecimals));
			});

			reportText += template.arg(yModelLabel).arg(formula).arg(parametersStr).arg(fitModels[s].error.toPrecision(aSettings.fDecimals));
		}
	}
	if (aHtml) {
		reportText = htmlTemplate.arg(reportText);
	}
	if (aCreateItem) {
		oldLTCount = mainWindow.activeDocument.itemCount("Layout Template");
		textItem = draw.text(reportText, "Report Special", "Graph", true, aGraph.uuid);
		if (oldLTCount === mainWindow.activeDocument.itemCount("Layout Template")) {
			textItem.width = mainWindow.activeDocument.curPage().width - aGraph.width;
			textItem.height = aGraph.height;
			textItem.left = aGraph.left;
			textItem.top = aGraph.top;
			textItem.translate(aGraph.width, 0.0);
			textItem.update();
			mainWindow.activeDocument.update();
		}
	}
	return reportText;
};

if (Env.GraphReporters) {
	Env.GraphReporters.push(new DefaultGraphReporter());
}

/******************************************************************************/

function SimpleGraphReporter() {
	"use strict";
	GraphReporterBase.call(this);
	
	this.fName = "Formula";
}

SimpleGraphReporter.prototype = new GraphReporterBase();

SimpleGraphReporter.prototype.report = function (aGraph, aCreateItem, aHtml, aSettings) {
	'use strict';
	var sCount, s, fitModels, yModels, reportText, graphProperties, horzAxsLabel, 
		yModelLabel, formula, parameters, template, parametersStr, p, parameterTemplate,
		textItem, htmlTemplate, oldLTCount;

	if (aGraph === undefined || !aGraph.isValid()) {
		throw new Error("Invalid Graph");
	}

	// precision = 4;
	htmlTemplate = "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"><title>Graph Report</title></head><body>%1</body></html>"; //%1 html body
	if (aHtml) {
		template = "<p><b>%1' = %2</b></p>"; //%1: label, %2: formula, %3: parameters, %4: comments
	} else {
		template = "%1' = %2";
	}
	parameterTemplate = '%1=%2;'; //%1: name, %2: value
	reportText = '';
	sCount = aGraph.seriesCount;
	fitModels = aGraph.fitModels;
	yModels = aGraph.yModels;
	graphProperties = aGraph.graphicProperties;
	horzAxsLabel = graphProperties.horzAxis.label;
	horzAxsLabel = horzAxsLabel.replace(/\([\w\W]*\)/, '');
	for (s = 0; s < sCount; ++s) {
		yModelLabel = yModels[s].label;
		if (yModelLabel.length === 0) {
			if (s === 0) {
				yModelLabel = 'Y';
			} else {
				yModelLabel = 'Y%1'.arg(s);
			}
		}
		formula = fitModels[s].formula;
		if (formula.length !== 0) {
			formula = formula.replace(/exp/g, 'EXP');
			formula = formula.replace(/x/g, horzAxsLabel);
			formula = formula.replace(/EXP/g, 'exp');
			parameters = fitModels[s].fitParams;
			parametersStr = '';
			for (p in parameters) {
				if (parameters.hasOwnProperty(p)) {
					formula = formula.replace(new RegExp("%1".arg(p)), parameters[p].toPrecision(aSettings.fDecimals));
				}
			}
			formula = formula.replace(/\+-/g, '-');
			formula = formula.replace(/-\+/g, '-');
			reportText += template.arg(yModelLabel).arg(formula);
		}
	}
	if (aHtml) {
		reportText = htmlTemplate.arg(reportText);
	}
	if (aCreateItem) {
		oldLTCount = mainWindow.activeDocument.itemCount("Layout Template");
		textItem = draw.text(reportText, "Report Special", "Graph", true, aGraph.uuid);
		if (oldLTCount === mainWindow.activeDocument.itemCount("Layout Template")) {
			textItem.width = mainWindow.activeDocument.curPage().width - aGraph.width;
			textItem.height = aGraph.height;
			textItem.left = aGraph.left;
			textItem.top = aGraph.top;
			textItem.translate(aGraph.width, 0.0);
			textItem.update();
			mainWindow.activeDocument.update();
		}
	}
	return reportText;
};

if (Env.GraphReporters) {
	Env.GraphReporters.push(new SimpleGraphReporter());
}

/******************************************************************************/

function GraphReportsHandler() {
	"use strict";
	
	function GraphReportsHandlerSettings() {
		var cSettingsKey = "GraphReportSpecial",
			cDefaultReportName = "Default Report",
			cDefaultDecimals = 4;
		
		Object.defineProperty(this, "fDefaultReportName", {
			value: cDefaultReportName,
			writable: false,
			configurable: false
		});
		
		Object.defineProperty(this, "fDefaultDecimals", {
			value: cDefaultDecimals,
			writable: false,
			configurable: false
		});

		Object.defineProperty(this, "fReportName", {
			get: function getReportName() {
				var s = new Settings(cSettingsKey);
				return s.value("ReportName", cDefaultReportName);
			},
			set: function setReportName(aReportName) {
				var s = new Settings(cSettingsKey);
				if (aReportName === cDefaultReportName) {
					s.remove("ReportName");
				} else {
					s.setValue("ReportName", aReportName);
				}
			}
		});
		
		Object.defineProperty(this, "fDecimals", {
			get: function getDecNumber() {
				var s = new Settings(cSettingsKey);
				return s.value("Decimals", cDefaultDecimals);
			},
			set: function setDecNumber(aNDec) {
				var s = new Settings(cSettingsKey);
				if (aNDec === cDefaultDecimals) {
					s.remove("Decimals");
				} else {
					s.setValue("Decimals", aNDec);
				}
			}
		});
	}
	
	this.fSettings = new GraphReportsHandlerSettings();
}

GraphReportsHandler.findReporterByName = function (aReportName) {
	"use strict";
	
	if (Env.GraphReporters === undefined) {
		return;
	}
	
	var i = 0;
	for (i = 0; i < Env.GraphReporters.length; ++i) {
		if (Env.GraphReporters[i].fName === aReportName) {
			return Env.GraphReporters[i];
		}
	}
	return undefined;
};

GraphReportsHandler.prototype.report = function (aGraph, aCreateItem, aUseHtml) {
	"use strict";
	
	var reporter = GraphReportsHandler.findReporterByName(this.fSettings.fReportName);
	
	if (!reporter) {
		reporter = GraphReportsHandler.findReporterByName(this.fSettings.fDefaultReportName);
	}
	
	if (!reporter) {
		return;
	}
	
	return reporter.report(aGraph, aCreateItem, aUseHtml, this.fSettings);
};

GraphReportsHandler.prototype.setup = function () {
	"use strict";
	
	var ui = '<?xml version="1.0" encoding="UTF-8"?><ui version="4.0"><class>WGraphReportSpecialSetupDialog</class><widget class="QDialog" name="WGraphReportSpecialSetupDialog"><property name="geometry"><rect><x>0</x><y>0</y><width>302</width><height>132</height></rect></property><property name="windowTitle"><string>Special Report Setup</string></property><layout class="QVBoxLayout" name="verticalLayout"><item><widget class="QGroupBox" name="groupBox"><property name="title"><string/></property><layout class="QGridLayout" name="gridLayout"><item row="0" column="0"><widget class="QLabel" name="label"><property name="text"><string>Report:</string></property></widget></item><item row="0" column="1"><widget class="QComboBox" name="fReportsComboBox"/></item><item row="1" column="0"><widget class="QLabel" name="label_2"><property name="text"><string>Decimals:</string></property></widget></item><item row="1" column="1"><widget class="QSpinBox" name="fDecimalsSpinBox"/></item></layout></widget></item><item><widget class="QDialogButtonBox" name="buttonBox"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="standardButtons"><set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set></property></widget></item></layout></widget><resources/><connections><connection><sender>buttonBox</sender><signal>accepted()</signal><receiver>WGraphReportSpecialSetupDialog</receiver><slot>accept()</slot><hints><hint type="sourcelabel"><x>248</x><y>254</y></hint><hint type="destinationlabel"><x>157</x><y>274</y></hint></hints></connection><connection><sender>buttonBox</sender><signal>rejected()</signal><receiver>WGraphReportSpecialSetupDialog</receiver><slot>reject()</slot><hints><hint type="sourcelabel"><x>316</x><y>260</y></hint><hint type="destinationlabel"><x>286</x><y>274</y></hint></hints></connection></connections></ui>',
		diag = Application.loadUi(ui), i, items = [],
		defReporter = this.fSettings.fReportName, curIndex = -1;
	
	if (Env.GraphReporters === undefined) {
		return;
	}
	for (i = 0; i < Env.GraphReporters.length; ++i) {
		items.push(Env.GraphReporters[i].fName);
	}
	
	curIndex = items.indexOf(defReporter);
	diag.widgets.fReportsComboBox.items = items;
	if (curIndex >= 0) {
		diag.widgets.fReportsComboBox.currentIndex = curIndex;
	} else {
		diag.widgets.fReportsComboBox.currentIndex = 0;
	}
	diag.widgets.fDecimalsSpinBox.value = this.fSettings.fDecimals;
	
	if (diag.exec()) {
		this.fSettings.fReportName = diag.widgets.fReportsComboBox.currentText;
		this.fSettings.fDecimals = diag.widgets.fDecimalsSpinBox.value;
	}
};
